/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package jturbofile.net;

import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import jturbofile.Config;
import jturbofile.gui.ConnectedUserUI;
import jturbofile.gui.LogPanel;

/**
 *
 * @author Rolf
 */
public class SendFileThread implements Runnable, Handler {

    private List<File> files;
    private PeerThread pt;
    private long totalSize, sentSize;
    private ConnectedUserUI userUI;
    private boolean keepGoing;
    private String currentFileName;
    private boolean fileAccepted;
    private boolean fileRejected;
    private long timeStamp, startTime;
    
    public SendFileThread(List<File> files, PeerThread pt, ConnectedUserUI userUI) {
        this.files = files;
        this.pt = pt;
        this.userUI = userUI;
        
        keepGoing = true;
        fileAccepted = false;
        fileRejected = false;
        
        pt.addHandler(this);
    }

    public void cancelSend() {
        keepGoing = false;
        LogPanel.singleton().logln("Cancel noticed");
        
        Packet p = new Packet(Packet.PacketType.FILECANCEL);
        p.addOption(currentFileName);
        pt.sendPacket(p);

        LogPanel.singleton().logln("Cancel sent");
    }
    
    public void run() {
        Packet p;
        
        LogPanel.singleton().logln("Files to send: "+files.size());
        
        for(File f : files) {
        
            if( !f.isFile() ) {
                continue;
            }
            
            String path = f.getAbsolutePath();
            totalSize = f.length();
            fileAccepted = false;
            fileRejected = false;
            sentSize = 0;
                    
            try {
                FileInputStream in = new FileInputStream(path);

                LogPanel.singleton().logln("Sending ["+path+"] to ["+pt+"]");

                userUI.setSendFileThread(this);
                userUI.getFileNameLabel().setText(path);
                userUI.getFileProgressBar().setValue(0);
                userUI.getFileProgressBar().setString("0%");
                userUI.startSend();
                
                /*
                 * Send FILEBEGIN with path to file
                 */
                p = new Packet(Packet.PacketType.FILEBEGIN);
                p.addOption(path);
                p.addOption(""+totalSize);
                pt.sendPacket(p);

                currentFileName = path;
                timeStamp = System.currentTimeMillis();
                startTime = timeStamp;
                
                /*
                 * Wait for FILEACCEPT
                 */
                
                LogPanel.singleton().logln("Waiting for fileaccept...");
                
                while(!fileAccepted) {
                    try {
                        Thread.sleep(100);
                        if( fileRejected ) {
                            LogPanel.singleton().logln("File ["+path+"] was rejected");
                            
                            userUI.getFileNameLabel().setText("");
                            userUI.getFileProgressBar().setValue(0);
                            userUI.getFileProgressBar().setString("0%");
                            userUI.endSend();

                            in.close();

                            pt.removeHandler(this);
                            
                            return;
                        }
                    }
                    catch(Exception e) {
                        LogPanel.singleton().logln("Error sleeping: "+e);
                    }
                }
                
                LogPanel.singleton().logln("File ["+path+"] was accepted");
                
                Config conf = Config.singleton();
                
                byte[] buffer = new byte[1024 * conf.getSpeed()];

                int length = in.read(buffer);

                while(length != -1) {
                    if( !keepGoing ) {
                        userUI.getFileNameLabel().setText("");
                        userUI.getFileProgressBar().setValue(0);
                        userUI.getFileProgressBar().setString("0%");
                        userUI.endSend();
                        
                        in.close();
                        
                        pt.removeHandler(this);
                        
                        return;
                    }
                    
                    byte[] data = new byte[length];
                    System.arraycopy(buffer, 0, data, 0, length);

                    /*
                     * Send FILEPART
                     */
                    long now = System.currentTimeMillis();
                    
                    p = new Packet(Packet.PacketType.FILEPART);
                    p.addOption(path);
                    p.setData(data);
                    
                    boolean ok = pt.sendPacket(p);
                    
                    float speed = (float)length / 1024.0f / (now - timeStamp) * 1000.0f;
                    
                    timeStamp = now;
                    
                    if( !ok ) {
                        LogPanel.singleton().logln("Error sending part of ["+path+"]");

                        userUI.getFileNameLabel().setText("");
                        userUI.getFileProgressBar().setValue(0);
                        userUI.getFileProgressBar().setString("0%");
                        userUI.endSend();
                        
                        in.close();
                        
                        return;
                    }

                    sentSize += length;
                    
                    int percent = (int)((float)sentSize / (float)totalSize * 100.0f);
                    
                    userUI.getFileProgressBar().setValue(percent);
                    
                    String speedStr = "kb";
                    if( speed > 1024.0f ) {
                        speedStr = "mb";
                        speed /= 1024.0f;
                    }
                    if( speed > 1024.0f ) {
                        speedStr = "gb";
                        speed /= 1024.0f;
                    }
                    if( speed > 1024.0f ) {
                        speedStr = "tb";
                        speed /= 1024.0f;
                    }
                    
                    speed = ((long)(speed * 10)) / 10.0f;
                    
                    userUI.getFileProgressBar().setString(sentSize+" / "+totalSize+" ["+speed+" "+speedStr+"/sec] - "+percent+"% Compression ["+p.getCompressionType()+"]");
                    
                    length = in.read(buffer);
                }

                in.close();

                /*
                 * Send FILEEND with path to file
                 */
                p = new Packet(Packet.PacketType.FILEEND);
                p.addOption(path);
                pt.sendPacket(p);

                userUI.getFileProgressBar().setValue(0);
                userUI.getFileProgressBar().setString("0%");
                userUI.getFileNameLabel().setText("");
                userUI.endSend();
                long now = System.currentTimeMillis();
                
                long ups = now - startTime;
                
                float time = ups / 1000.f;
                time = ((long)(time * 10)) / 10.0f;
                
                float speed = totalSize / 1024.0f / time;
                
                String speedStr = "kb";
                if( speed > 1024.0f ) {
                    speedStr = "mb";
                    speed /= 1024.0f;
                }
                if( speed > 1024.0f ) {
                    speedStr = "gb";
                    speed /= 1024.0f;
                }
                if( speed > 1024.0f ) {
                    speedStr = "tb";
                    speed /= 1024.0f;
                }

                speed = ((long)(speed * 10)) / 10.0f;
                
                LogPanel.singleton().logln("Succesfully sent ["+path+"] to ["+pt+"], time taken ["+time+"], speed ["+speed+" "+speedStr+"/sec]");
            }
            catch(Exception e) {
                LogPanel.singleton().logln("Error sending file: "+e);
            }
        }
        
        pt.removeHandler(this);
    }

    public long getTotalSize() {
        return totalSize;
    }
    
    public long getSentSize() {
        return sentSize;
    }

    public boolean handlePacket(Packet p, PeerThread pt) {
        if( p.getType() == Packet.PacketType.FILEACCEPT ) {
            if(p.getOptions().get(0).equals(currentFileName)) {
                //Correct accept
                
                fileAccepted = true;
                        
                return true;
            }
        }
        else if( p.getType() == Packet.PacketType.FILEREJECT ) {
            if(p.getOptions().get(0).equals(currentFileName)) {
                //Correct reject
                
                fileRejected = true;
                
                return true;
            }
        }
        
        return false;
    }
    
}
